/***************************************************************************************
 * Copyright (c) 2014-2022 Zihao Yu, Nanjing University
 *
 * NEMU is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *
 * See the Mulan PSL v2 for more details.
 ***************************************************************************************/

#include "sdb.h"

#define NR_WP 32

word_t expr(char *e, bool *success);
typedef struct watchpoint
{
  int NO;
  struct watchpoint *next;
  /* TODO: Add more members if necessary */
  char expr[64];
  word_t data;
} WP;

static WP wp_pool[NR_WP] = {};
static WP *head = NULL, *free_ = NULL;

void init_wp_pool()
{
  int i;
  for (i = 0; i < NR_WP; i++)
  {
    wp_pool[i].NO = i;
    wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
  }

  head = NULL;
  free_ = wp_pool;
}

/* TODO: Implement the functionality of watchpoint */
WP *new_wp(char *e)
{
  if (!free_)
  {
    P_ERROR("The pool of watchpoint overflows");
    assert(free_ < wp_pool + NR_WP);
    return NULL;
  }
  bool success;
  word_t x = expr(e, &success);
  if (!success)
  {
    P_ERROR("Bad experssion");
    return NULL;
  }
  WP *temp = head;
  head = free_;
  free_ = free_->next;
  head->next = temp;
  strcpy(head->expr, e);
  head->data = x;
  return head;
}
void free_wp(int no)
{
  WP *pre = NULL;
  for (WP *p = head; p; p = p->next)
  {
    if (p->NO == no)
    {
      if (pre == NULL)
        head = p->next;
      else
        pre->next = p->next;
      p->next = free_;
      free_ = p;
      return;
    }
    pre = p;
  }
  printf("NO.%d was not found\n", no);
  return;
}
void wp_display()
{
  for (WP *p = head; p; p = p->next)
    printf("[NO.%d][expr:%s]:0x%08x\n", p->NO, p->expr, p->data);
}
bool check_wp()
{
  bool success;
  word_t value;
  for (WP *p = head; p; p = p->next)
  {
    value=expr(p->expr, &success);
    if (p->data != value){
      p->data=value;
      return true;
    }
  }
  return false;
}